#include <stdio.h>
#include <math.h>
#include "SDL/SDL.h"
#include "BM_level.h"

int smile_level[1][16][22] = {{
		{ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2},//
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,1,1,1,2,2,1,1,1,1,1,1,1,1,2,2,10,1,1,1,1,2},//THIS HAS THE START
		{ 2,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,1,1,1,1,2},//
		{ 2,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,1,1,1,1,2},//
		{ 2,1,1,2,2,2,2,1,1,1,1,1,1,2,2,2,2,1,1,1,1,2},//
		{ 2,1,1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,2},//
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,2},//
		{ 2,1,1,1,2,2,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,2},//
		{ 2,1,1,1,1,11,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,2},//THIS has the EXIT
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2},//
		{ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2}}
		};

GLuint block_texture[MAX_BLOCK_TYPES];

BMBlock::BMBlock(){
        x = 0.0f;
        y = 0.0f;
        z = -6.0f;
        x_rot = 0.0f;
        y_rot = 0.0f;
        z_rot = 0.0f;
		type = BLOCK_0;
		dr = DRAW_FRONT + DRAW_BACK + DRAW_BOTTOM + DRAW_LEFT + DRAW_RIGHT + DRAW_TOP;
}

void BMBlock::reset(){
        x = 0.0f;
        y = 0.0f;
        z = -6.0f;
        x_rot = 0.0f;
        y_rot = 0.0f;
        z_rot = 0.0f;
		type = BLOCK_0;
}

void BMBlock::setType(int t){
	type = t;
}

int BMBlock::getType(){
	return type;
}

void BMBlock::setSetting(int s){
	setting = s;
}

int BMBlock::getSetting(){
	return setting;
}

void BMBlock::setMap(float q, float w, float s){
	map_x = q;
	map_y = w;
	map_z = s;
}

/*******************************************************************************/
void BMBlock::move(float q, float w, float s){
	x = q;
	y = w;
	z = s;
}

/*******************************************************************************/
void BMBlock::rotate(float q, float w, float s){
	x_rot = q;
	y_rot = w;
	z_rot = s;
}

/*******************************************************************************/
int BMBlock::draw(GLuint texture, float scalar){

    /* Reset the view */
    //glLoadIdentity( ); // don't do this here otherwise we will not be able to user our camera

    //glTranslatef( x , y , z );
	//x = x0 + rsin() cos&    y = y0 + rsin() sin&   z = z0 + rcos()
    //glTranslatef( (x + map_x) * sin(y_rot) * cos(x_rot)  + x+ map_x, (y + map_y) * sin(y_rot) * sin(x_rot) + y+ map_y, (z+map_z) * cos(y_rot)  + z + map_z);
	/*glTranslatef( (x + map_x), (y + map_y) ,  z + map_z);
	//	glTranslatef( 0 , 0 , -6.0f );
    glRotatef( x_rot, 1.0f, 0, 0);
    glRotatef( y_rot, 0, 1.0f,  0);
    glRotatef( z_rot, 0, 0, 1.0f);

    glBindTexture( GL_TEXTURE_2D, texture);

    glBegin( GL_QUADS );
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Top Left Of The Texture and Quad

    // Back Face
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad

    // Top Face
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad

    // Bottom Face
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad

    // Right face
    glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	// Bottom Left Of The Texture and Quad

    // Left Face
    glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	// Top Left Of The Texture and Quad
*/

    // this is done in the camera function so we don't need this - that's why it's commented
	/*glTranslatef( (x ), (y ) ,  z );
	//	glTranslatef( 0 , 0 , -6.0f );
    glRotatef( x_rot, 1.0f, 0, 0);
    glRotatef( y_rot, 0, 1.0f,  0);
    glRotatef( z_rot, 0, 0, 1.0f);*/

    glBindTexture( GL_TEXTURE_2D, texture);
    float one[2] = { (scalar * -1.0f)/2, (scalar * 1.0f)/2};

    glBegin( GL_QUADS );
	// Front Face
	if(dr & DRAW_FRONT){
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Top Left Of The Texture and Quad
	}
	if(dr & DRAW_BACK){
    // Back Face
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Bottom Left Of The Texture and Quad
	}
	if(dr & DRAW_TOP){
    // Top Face
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Right Of The Texture and Quad
	}
	if(dr & DRAW_RIGHT){
    // Right face
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Left Of The Texture and Quad
	}
	if(dr & DRAW_LEFT){
    // Left Face
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Right Of The Texture and Quad
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[1]+map_z+z);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[1]+map_y+y,one[0]+map_z+z);	// Top Left Of The Texture and Quad
	}
	if(dr & DRAW_BOTTOM){
    // Bottom Face
    glTexCoord2f(1.0f, 1.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Top Right Of The Texture and Quad
    glTexCoord2f(0.0f, 1.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[0]+map_z+z);	// Top Left Of The Texture and Quad
    glTexCoord2f(0.0f, 0.0f); glVertex3f(one[1]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Left Of The Texture and Quad
    glTexCoord2f(1.0f, 0.0f); glVertex3f(one[0]+map_x+x,one[0]+map_y+y,one[1]+map_z+z);	// Bottom Right Of The Texture and Quad
	}
	glEnd();

	return 1;
}

/*******************************************************************************/

void BMBlock::setDR(char d){
	dr = d;
}

/*******************************************************************************/


char BMBlock::getDR(){
	return dr;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
BMLevel::BMLevel(){
    x = 0.0f;
    y = 0.0f;
    z = -1.0f;
    x_rot = 0.0f;
    y_rot = 0.0f;
    z_rot = -1.0f;
    scalar = 8.0f;
    time_total = -1;
    time_left = 0;
    level = 0;
    total_start= 0;

    skybox_width = 50;
    skybox_height = 50;
    skybox_length = 50;
    skybox_x = skybox_y = skybox_z = -25.0f;
}

void BMLevel::reset()
{
    x = 0.0f;
    y = 0.0f;
    z = -1.0f;
    x_rot = 0.0f;
    y_rot = 0.0f;
    z_rot = -1.0f;
    scalar = 8.0f;
    time_total = -1;
    time_left = 0;
    level = 0;
    total_start= 0;
}

void BMLevel::freeLevel()
{
    reset();
    for(int ly = 0; ly < height; ly++){
		for(int lz = 0; lz < length; lz ++){
			for(int lx = 0; lx < width; lx ++){
					block[lx][ly][lz].reset();
			}
		}
	}

	for(int i = 0; i < MAX_BLOCK_TYPES; i++){
		//block_texture[i] = 0;
		memset(&block_texture, 0, sizeof(MAX_BLOCK_TYPES));
		ani_tex[i].freeTex();
	}
}

/*******************************************************************************/

void BMLevel::draw_skybox(){

    // draw BACK texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[0].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y,	skybox_z);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height, skybox_z);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x, skybox_y + skybox_height, skybox_z);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x, skybox_y, skybox_z);
    glEnd();

    // draw FRONT texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[1].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x,	skybox_y, skybox_z + skybox_length);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x,	skybox_y + skybox_height, skybox_z + skybox_length);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height, skybox_z + skybox_length);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y,	skybox_z + skybox_length);
	glEnd();

	// draw BOTTOM texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[2].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x, skybox_y, skybox_z);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x, skybox_y, skybox_z + skybox_length);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y, skybox_z + skybox_length);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y, skybox_z);
	glEnd();

	// draw TOP texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[3].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height, skybox_z);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height, skybox_z + skybox_length);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x, skybox_y + skybox_height, skybox_z + skybox_length);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x, skybox_y + skybox_height, skybox_z);
	glEnd();

	// draw LEFT texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[4].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x, skybox_y + skybox_height, skybox_z);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x, skybox_y + skybox_height, skybox_z + skybox_length);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x, skybox_y, skybox_z + skybox_length);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x, skybox_y, skybox_z);
	glEnd();

	// draw RIGHT texture
    glBindTexture(GL_TEXTURE_2D, skybox_textures[5].getTex());
    glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y,	skybox_z);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(skybox_x + skybox_width, skybox_y,	skybox_z + skybox_length);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height,	skybox_z + skybox_length);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(skybox_x + skybox_width, skybox_y + skybox_height,	skybox_z);
	glEnd();
}

void BMLevel::draw(){

    draw_skybox();
	
    for(int i = 0; i < MAX_BLOCK_TYPES; i++){
		block_texture[i] = ani_tex[i].getTex(ani_tex[i].getCurTex());
		ani_tex[i].updateTex();
	}
	for(int ly = 0; ly < height ; ly++){
		for(int lz = 0; lz < depth; lz ++){
			for(int lx = 0; lx < width; lx ++){
					block[lx][ly][lz].move(x,y,z);
					block[lx][ly][lz].rotate(x_rot,y_rot,z_rot);
			}
		}
	}
	for(int ly = 0; ly < height ; ly++){
		for(int lz = 0; lz <  depth; lz ++){
			for(int lx = 0; lx < width; lx ++){
				if(block[lx][ly][lz].getType() != BLOCK_0 && block[lx][ly][lz].getType() != BLOCK_12){
					block[lx][ly][lz].draw(block_texture[block[lx][ly][lz].getType()-1],scalar);
				}
			}
		}
	}
}

/*******************************************************************************/

/* Reads the header of the level file */
/* level name, width, length, height, scalar, level, time_total, foldername*/
// @param FILE * - file must opened already
int BMLevel::readLevelHeader(FILE *file)
{
    //FILE *file;

    char buffer[100];

    int line = 0;

    /*file = fopen(src, "r"); // open our config file
    if (!file)
        return 0;*/

    while (line < 9)
    {
        fgets (buffer , 100 , file);

        switch (line)
        {
            case 0:
                sscanf(buffer, "%s", name);
            break;

            case 1:
                sscanf(buffer, "%d", &depth);
            break;

            case 2:
                sscanf(buffer, "%d", &width);
            break;

            case 3:
                sscanf(buffer, "%d", &length);
            break;

            case 4:
                sscanf(buffer, "%d", &height);
            break;

            case 5:
                sscanf(buffer, "%f", &scalar);
            break;

            case 6:
                sscanf(buffer, "%d", &level);
            break;

            case 7:
                sscanf(buffer, "%d", &time_total);
            break;

            case 8:
                sscanf(buffer, "%s", foldername);
            break;
        }
        line++;
    }

    return 1;
}

int BMLevel::load(char filename[128]){
	FILE *file;
	
	file = fopen(filename, "r");
	memset(&foldername, 0, sizeof(char));
	memset(&cur_folder, 0, sizeof(char));
	int total_anitex[MAX_BLOCK_TYPES];
	int delays[MAX_BLOCK_TYPES][MAX_ANITEX];
	int type = 0;
	readLevelHeader(file);

	for(int i = 0; i< MAX_BLOCK_TYPES; i++) {
		fscanf(file,"%d\n",&total_anitex[i]);
		for(int u = 0; u < total_anitex[i]; u ++){
			fscanf(file,"%d,",&delays[i][u]);
		}
		fscanf(file,"\n");
	}
	
    for(int ly = 0; ly < height ; ly++){
		for(int lz=0; lz < depth; lz++) {
            for(int lx = 0; lx < width; lx ++){
                fscanf(file,"%d,",&type);
                switch(type){
                    case BLOCK_0:
                        block[lx][ly][lz].setType(BLOCK_0);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_1:
                        block[lx][ly][lz].setType(BLOCK_1);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_2:
                        block[lx][ly][lz].setType(BLOCK_2);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_3:
                        block[lx][ly][lz].setType(BLOCK_3);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_4:
                        block[lx][ly][lz].setType(BLOCK_4);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_5:
                        block[lx][ly][lz].setType(BLOCK_5);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_6:
                        block[lx][ly][lz].setType(BLOCK_6);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_7:
                        block[lx][ly][lz].setType(BLOCK_7);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_8:
                        block[lx][ly][lz].setType(BLOCK_8);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_9:
                        block[lx][ly][lz].setType(BLOCK_9);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_10:
                        block[lx][ly][lz].setType(BLOCK_10);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        start[total_start][0] = lx  * scalar;
                        start[total_start][1] = ly * scalar +   scalar/2;
                        start[total_start][2] = lz  * scalar;
                        total_start ++;
                        break;
                    case BLOCK_11:
                        block[lx][ly][lz].setType(BLOCK_11);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    case BLOCK_12:
                        block[lx][ly][lz].setType(BLOCK_12);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                    default:
                        block[lx][ly][lz].setType(BLOCK_0);
                        block[lx][ly][lz].setMap(lx  * scalar,ly  * scalar,lz  * scalar);
                        break;
                }
				
            }
            fscanf(file,"\n");
        }
         fscanf(file,"=\n");
	}

	fclose(file);
	sprintf(cur_folder,"%s/song.mp3",foldername);
	song.load(cur_folder);
	for(int i = 0; i< MAX_BLOCK_TYPES; i++){
		sprintf(cur_folder,"%s/blocks/%d",foldername,i+1);
        if(!ani_tex[i].load(total_anitex[i],cur_folder))
            return 0;
		for(int u = 0; u < total_anitex[i]; u ++){
			ani_tex[i].setDelay(u,delays[i][u]);
		}

	}
	//Level Drawing Optimizing Parser
	for(int lz=0; lz < depth; lz++) {
        for(int ly = 0; ly < height ; ly++){
            for(int lx = 0; lx < width; lx ++){
				block[lx][ly][lz].setDR(DRAW_FRONT + DRAW_BACK + DRAW_BOTTOM + DRAW_LEFT + DRAW_RIGHT + DRAW_TOP);
			}
		}
	}
	
	for(int lz = 0; lz <  depth; lz ++){
        for(int ly = 0; ly < height ; ly++){
			for(int lx = 0; lx < width; lx ++){
				if(ly - 1 >= 0 && block[lx][ly-1][lz].getType() != BLOCK_0 && block[lx][ly-1][lz].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_BOTTOM);

				if(ly + 1 < height && block[lx][ly+1][lz].getType() != BLOCK_0 && block[lx][ly+1][lz].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_TOP);

				if(lz + 1 < length && block[lx][ly][lz+1].getType() != BLOCK_0 && block[lx][ly][lz+1].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_FRONT);

				if(lz - 1 >= 0 && block[lx][ly][lz-1].getType() != BLOCK_0 && block[lx][ly][lz-1].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_BACK);

				if(lx + 1 < width && block[lx+1][ly][lz].getType() != BLOCK_0 && block[lx+1][ly][lz].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_RIGHT);

				if(lx - 1 >= 0 && block[lx-1][ly][lz].getType() != BLOCK_0 && block[lx-1][ly][lz].getType() != BLOCK_12)
					block[lx][ly][lz].setDR(block[lx][ly][lz].getDR() - DRAW_LEFT);
			}
		}
	}

	// load sky box textures now
	char path[256];
	memset(&path, 0, sizeof(char));
	sprintf(path, "%s/skybox/back.bmp", foldername);

	// back bmp
    skybox_textures[0].load(path, true);

    sprintf(path, "%s/skybox/front.bmp", foldername);

    // front bmp
    skybox_textures[1].load(path);

    sprintf(path, "%s/skybox/bottom.bmp", foldername);

    // bottom bmp
    skybox_textures[2].load(path);

    sprintf(path, "%s/skybox/top.bmp", foldername);

    // top bmp
    skybox_textures[3].load(path);

    sprintf(path, "%s/skybox/left.bmp", foldername);

    // left bmp
    skybox_textures[4].load(path);

    sprintf(path, "%s/skybox/right.bmp", foldername);

    // right bmp
    skybox_textures[5].load(path);

    return 1;
}
void BMLevel::begin(){
	song.play();
}

void BMLevel::end(){
	song.stop();
	song.free();
}

/*******************************************************************************/
void BMLevel::move(float in_x, float in_y, float in_z){
	x = in_x;
	y = in_y;
	z = in_z;
}

/*******************************************************************************/
void BMLevel::move_skybox(float in_x, float in_y, float in_z){
    skybox_x = in_x;
	skybox_y = in_y;
	skybox_z = in_z;
}

/*******************************************************************************/
void BMLevel::modify_skybox(float width, float height, float length){
    skybox_width = width;
	skybox_height = height;
	skybox_length = length;
}

/*******************************************************************************/
void BMLevel::rotate(float in_x, float in_y, float in_z){
	x_rot = in_x;
	y_rot = in_y;
	z_rot = in_z;
}


void BMLevel::getStart(int i, float *sx, float *sy, float *sz){
	*sx = start[i][0];
	*sy = start[i][1];
	*sz = start[i][2];
}

 
 int binarySearch(int array[],int max, int value){
	int first = 0, last = max - 1, middle, position = -1;
	bool found = false;
	while(!found && first <=last){
		middle = (first + last) / 2;
		if(array[middle] == value){
			found = true;
			position = middle;
		}else
			if(array[middle] > value)
				last = middle - 1;
			else
				first = middle  + 1;
	}
	return position;
 }
 

int BMLevel::collision(float cx, float cy, float cz, int xtra){ //uses a binary search method for speed
	/*int block_x = -1, block_y = -1, block_z = -1, middle,first = 0, last;
	float scalarhalf  = scalar / 2;
	
	last = height - 1;
	while(!(block_y+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cy + scalarhalf &&  (middle + 1) * scalar >= cy + scalarhalf)){
			block_y = middle;
		}else{
			if( middle * scalar > cy + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	cout << "hmiddle: " << middle;
	first = 0;
	last = width - 1;
	while(!(block_x+1) && first <= last){
		middle = (first + last) /2;
		//cout << "middle " << middle << endl;
		if( (middle * scalar < cx + scalarhalf &&  (middle + 1) * scalar >= cx + scalarhalf)){
			block_x = middle;
			break;
		}else{
			if( middle * scalar > cx + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	cout << "\nwmiddle: " << middle;
	first = 0;
	last =  depth - 1;
	while(!(block_z+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cz + scalarhalf &&  (middle + 1) * scalar >= cz + scalarhalf)){
			block_z = middle;
		}else{
			if( middle * scalar > cz + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	cout << "\ndmiddle: " << middle;
	cout << endl;
	cout << "\n" << block[0][2][1].getType();
	cout << "\n" << block[block_x][block_y][block_z].getType();
	if(block[block_x][block_y][block_z].getType() != BLOCK_0){
		return 1;
	}
	return 0;*/
	Point3D *point;	point = (Point3D*)malloc(sizeof(Point3D));
	int block_x = -1, block_y = -1, block_z = -1, middle,first = 0, last;
	float scalarhalf  = scalar / 2;
	
	last = height - 1;
	while(!(block_y+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cy + scalarhalf &&  (middle + 1) * scalar >= cy + scalarhalf)){
			block_y = middle;
		}else{
			if( middle * scalar > cy + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	first = 0;
	last = width - 1;
	while(!(block_x+1) && first <= last){
		middle = (first + last) /2;
		//cout << "middle " << middle << endl;
		if( (middle * scalar < cx + scalarhalf &&  (middle + 1) * scalar >= cx + scalarhalf)){
			block_x = middle;
			break;
		}else{
			if( middle * scalar > cx + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	first = 0;
	last =  depth - 1;
	while(!(block_z+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cz + scalarhalf &&  (middle + 1) * scalar >= cz + scalarhalf)){
			block_z = middle;
		}else{
			if( middle * scalar > cz + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	point->x = (float)block_x * scalar - scalar/2;
	point->y = (float)block_y * scalar - scalar/2;
	point->z = (float)block_z * scalar - scalar/2;
	
	int x = (int)(point->x / scalar + scalar/2);
	int y = (int)(point->y / scalar + scalar/2);
	int z = (int)(point->z / scalar + scalar/2);
	
	free(point);
	if(block[x][y][z].getType() != BLOCK_0 && block[x][y][z].getType() != xtra){
		return 1;
	}
	return 0;
}


float BMLevel::getScalar(){
	return scalar;
}

int BMLevel::getDepth()
{
    return depth;
}

Point3D* BMLevel::getBlock(float cx, float cy, float cz){
	Point3D *point;
	point = (Point3D*)malloc(sizeof(Point3D));
int block_x = -1, block_y = -1, block_z = -1, middle,first = 0, last;
	float scalarhalf  = scalar / 2;
	first = 0;
	last = height - 1;
	while(!(block_y+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cy + scalarhalf &&  (middle + 1) * scalar >= cy + scalarhalf)){
			block_y = middle;
		}else{
			if( middle * scalar > cy + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	first = 0;
	last = width - 1;
	while(!(block_x+1) && first <= last){
		middle = (first + last) /2;
		//cout << "middle " << middle << endl;
		if( (middle * scalar < cx + scalarhalf &&  (middle + 1) * scalar >= cx + scalarhalf)){
			block_x = middle;
			break;
		}else{
			if( middle * scalar > cx + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	first = 0;
	last =  depth - 1;
	while(!(block_z+1) && first <= last){
		middle = (first + last) /2;
		if(( middle * scalar < cz + scalarhalf &&  (middle + 1) * scalar >= cz + scalarhalf)){
			block_z = middle;
		}else{
			if( middle * scalar > cz + scalarhalf){
				last = middle - 1;
			}else{
				first = middle + 1;
			}
		}
	}
	
	point->x = (float)block_x * scalar - scalar/2;
	point->y = (float)block_y * scalar - scalar/2;
	point->z = (float)block_z * scalar - scalar/2;
	return point;
}

int BMLevel::getBlockType(int cx, int cy, int cz){
	return block[cx][cy][cz].getType();
}

BMLevel::~BMLevel(){
}
